package io.github.bffcorreia.fole;

import android.view.View;
import android.view.ViewTreeObserver;
import android.view.animation.Animation;

public class Config {
    private final Fole fole;
    private String text;
    private int maxLines;
    private int maxChars;
    private String ellipsisPlaceholder;
    private View toggleView;
    private FoleCallback callback;
    private Animation expandAnimation;
    private Animation collapseAnimation;
    private boolean isTextViewExpanded;

    Config(Fole fole) {
        this.fole = fole;
        this.text = null;
        this.ellipsisPlaceholder = "...";
    }

    public Config text(String text) {
        this.text = text;
        return this;
    }

    public Config maxLines(int maxLines) {
        Preconditions.checkArgument(maxLines > 0, "MaxLines must not be 0.");
        Preconditions.checkState(this.maxChars == 0, "MaxChars and MaxLines can not be used at same time.");
        this.maxLines = maxLines;
        return this;
    }

    public Config maxChars(int maxChars) {
        Preconditions.checkArgument(maxChars > 0, "MaxChars must not be 0.");
        Preconditions.checkState(this.maxLines == 0, "MaxLines and MaxChars can not be used at same time.");
        this.maxChars = maxChars;
        return this;
    }

    public Config ellipsisPlaceholder(String ellipsizePlaceholder) {
        Preconditions.checkArgument(ellipsizePlaceholder != null, "Placeholder must not be null.");
        this.ellipsisPlaceholder = ellipsizePlaceholder;
        return this;
    }

    public Config animation(Animation animation) {
        Preconditions.checkArgument(animation != null, "Animation must not be null.");
        this.expandAnimation = animation;
        this.collapseAnimation = animation;
        return this;
    }

    public Config expandAnimation(Animation expandAnimation) {
        Preconditions.checkArgument(expandAnimation != null, "Expand Animation must not be null.");
        this.expandAnimation = expandAnimation;
        return this;
    }

    public Config collapseAnimation(Animation collapseAnimation) {
        Preconditions.checkArgument(collapseAnimation != null, "Collapse Animation must not be null.");
        this.collapseAnimation = collapseAnimation;
        return this;
    }

    public void toggleView(View toggleView) {
        toggleView(toggleView, null);
    }

    public void toggleView(View toggleView, FoleCallback callback) {
        Preconditions.checkArgument(toggleView != null, "Toggle view must not be null.");
        this.toggleView = toggleView;
        this.callback = callback;

        addOnExpandableViewClickListener();
        handleViewState();
        initText();
    }

    private void initText() {
        if (this.text == null) {
            this.text = this.fole.textView.getText().toString();
        }
        this.fole.textView.setText(this.text);
    }

    private void addOnExpandableViewClickListener() {
        this.toggleView.setClickable(true);
        this.toggleView.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {
                Config.this.onActionPerformed();
            }
        });
    }

    private void onActionPerformed() {
        if (this.isTextViewExpanded) {
            handleViewState();
            this.fole.textView.requestLayout();
            startAnimation(this.collapseAnimation);
        } else {
            this.isTextViewExpanded = true;
            this.fole.textView.setText(this.text);
            startAnimation(this.expandAnimation);
            addActionInfoIfCallbackIsSet(true);
        }
    }

    private void addActionInfoIfCallbackIsSet(boolean wasExpanded) {
        if (this.callback != null) {
            if (wasExpanded) {
                this.callback.onTextExpand();
            } else {
                this.callback.onTextCollapse();
            }
        }
    }

    private void handleViewState() {
        Preconditions.checkState((this.maxLines > 0) || (this.maxChars > 0), "You need to add MaxLines or MaxChars.");
        if (this.maxLines > 0) {
            addListener(new MaxLinesStateHandler(this.fole.textView, this.ellipsisPlaceholder, this.maxLines));
        } else {
            addListener(new MaxCharsStateHandler(this.fole.textView, this.ellipsisPlaceholder, this.maxChars));
        }
    }

    private void addListener(final TextViewStateHandler textViewStateHandler) {
        ViewTreeObserver treeObserver = this.fole.textView.getViewTreeObserver();

        treeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            public void onGlobalLayout() {
                if (textViewStateHandler.isTextExpanded()) {
                    Config.this.fole.textView.setText(textViewStateHandler.ellipsizedText());
                    Config.this.isTextViewExpanded = false;
                    Config.this.addActionInfoIfCallbackIsSet(false);
                } else {
                    Config.this.isTextViewExpanded = true;
                }
                Config.this.showOrHideToggleViewIfNeeded();
                Config.this.fole.textView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
            }
        });
    }

    private void showOrHideToggleViewIfNeeded() {
        if (this.toggleView == this.fole.textView) {
            return;
        }
        if (this.isTextViewExpanded) {
            this.toggleView.setVisibility(View.GONE);
        } else {
            this.toggleView.setVisibility(View.VISIBLE);
        }
    }

    private void startAnimation(Animation animation) {
        if (animation == null) {
            return;
        }
        this.fole.textView.clearAnimation();
        this.fole.textView.startAnimation(animation);
    }
}
